package com.simafei.flow.core.api.impl;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.IdUtil;
import com.simafei.flow.core.ExecutionResult;
import com.simafei.flow.core.api.Api;
import com.simafei.flow.core.api.ApiAdapter;
import com.simafei.flow.core.exception.ApiCallException;
import lombok.RequiredArgsConstructor;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author fengpengju
 */
@RequiredArgsConstructor
public class ApiExecutor {

    private final List<ApiAdapter> apiAdapters;

    public ApiExecutor() {
        apiAdapters = new ArrayList<>();
        try {
            for (Class<?> aClass : ClassUtil.scanPackageBySuper(getClass().getPackageName(), ApiAdapter.class)) {
                ApiAdapter adapter = (ApiAdapter) aClass.getDeclaredConstructor().newInstance();
                apiAdapters.add(adapter);
            }
        } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ignored) {
        }
    }

    public ExecutionResult execute(Api api, Map<String, Object> params) {
        return doExecute(api, params);
    }

    public List<ExecutionResult> execute(Api api, List<Map<String, Object>> params) {
        return doExecute(api, params);
    }

    private ExecutionResult doExecute(Api api, Map<String, Object> params) {
        Optional<ApiAdapter> first = apiAdapters.stream()
                .filter(apiAdapter -> apiAdapter.serializeType() == api.getSerializeType()).findFirst();
        if (first.isPresent()) {
            return ExecutionResult.builder()
                    .results(first.get().exchange(api, params))
                    .build();
        } else {
            throw new ApiCallException("Serialize type not support");
        }
    }

    private List<ExecutionResult> doExecute(Api api, List<Map<String, Object>> params) {
        List<ExecutionResult> results = new ArrayList<>();
        Optional<ApiAdapter> first = apiAdapters.stream()
                .filter(apiAdapter -> apiAdapter.serializeType() == api.getSerializeType()).findFirst();
        if (first.isPresent()) {
            for (Map<String, Object> param : params) {
                List<Map<String, Object>> exchange = first.get().exchange(api, param);
                results.add(ExecutionResult.builder()
                        .inputParams(param)
                        .results(exchange)
                        .build());
            }
            return results;
        } else {
            throw new ApiCallException("Serialize type not support");
        }
    }

    public String template(String templateName) {
        String template = ResourceUtil.readUtf8Str(templateName + ".groovy");
        template = template.replace("_Resolver", IdUtil.getSnowflakeNextIdStr());
        return template;
    }
}
